<?php
/**
 * 由 phpmailer 封装的邮箱发送机制
 * User: Joshua Conero
 * Date: 2019/7/19
 * Time: 11:47
 * Email: conero@163.com
 */

namespace app\common\utils;




use hyang\Util;
use PHPMailer\PHPMailer\PHPMailer;
use think\facade\Config;
use think\facade\Env;

class Mail
{
    const SendName = 'Joshua Conero';
    const DefaultKey = 'email.default';                     // 默认模板
    const DefaultSubjectKey = 'email.default_subject';      // 默认主题
    const SubjectSuffiex = '_subject';                      // subject 后缀

    const EmailHost = 'email.host';
    const EmailUsername = 'email.username';
    const EmailPassword = 'email.password';
    const EmailCharset = 'email.charset';
    const EmailSsl = 'email.ssl';                           // 安全层
    const EmailPort = 'email.port';                         // 端口号，默认为25

    const SessionCodeKey = 'email_code';

    /**
     * @var PHPMailer
     */
    private static $_mail;
    private static $_config = [];
    private static $_lastErrorMsg;
    static $key;
    static $rendData = [];

    /**
     * 获取配置文件
     * @return array
     */
    static function getConf(){
        if(empty(self::$_config)){
            $email = [];
            $email['host'] = Env::get(self::EmailHost);
            $email['username'] = Env::get(self::EmailUsername);
            $email['password'] = Env::get(self::EmailPassword);
            $email['charset'] = Env::get(self::EmailCharset);
            $email['ssl'] = Env::get(self::EmailSsl);
            $email['port'] = Env::get(self::EmailPort);
            self::$_config = $email;
        }
        return self::$_config;
    }

    /**
     * @return PHPMailer
     * @throws \PHPMailer\PHPMailer\Exception
     */
    static function mail(){
        if(empty(self::$_mail)){
            $conf = self::getConf();
            $mail = new PHPMailer(true);
            $mail->isSMTP();
            // 安全层
            if($conf['ssl'] ?? false){
                $mail->SMTPSecure = 'ssl';
            }
            // 端口号
            if($conf['port'] ?? false){
                $mail->Port = $conf['port'];
            }

            $mail->Host = $conf['host'];
            $mail->SMTPAuth = true;
            $mail->Password = $conf['password'];
            $mail->Username = $conf['username'];
            $mail->CharSet = $conf['charset'];
            $mail->setFrom($mail->Username, Env::get('system_name', self::SendName));
            self::$_mail = $mail;
        }
        return self::$_mail;
    }

    /**
     * 生成验证码
     * @param mixed ...$emails
     * @return bool
     * @throws \PHPMailer\PHPMailer\Exception
     */
    static function sendCode(...$emails){
        $email = self::mail();
        try{
            $email->clearAddresses();   // 删除所有历史地址
            foreach ($emails as $toMail){
                if(is_array($toMail)){
                    $email->addAddress($toMail[0], $toMail[1]);
                }else if(is_string($toMail)){
                    $email->addAddress($toMail);
                }
            }
            $email->isHTML(true);
            // 内容发送
            $key = self::$key;
            $tpl = Config::get(self::DefaultKey);
            $subject = Config::get(self::DefaultSubjectKey);
            $tpl = $key? Config::get('email.'.$key, $tpl) : $tpl;
            $subject = $key? Config::get('email.'.$key.'_subject', $subject) : $subject;
            $code = self::code();
            session(self::SessionCodeKey, [
                'code'  => $code,
                'time'  => time()
            ]);
            $email->Body = Util::rend($tpl, array_merge(self::$rendData, [
                'code'  => $code,
                'minute'=> Config::get('email.minute')
            ]));
            // 主题
            $email->Subject = $subject;


            $email->send();
            self::$_lastErrorMsg = null;
            return true;
        }catch (\Exception $e){
            self::$_lastErrorMsg = $email->ErrorInfo;
        }
        return false;
    }

    /**
     * 获取/生成验证码
     * @param null|string $id
     * @return int
     */
    static function code($id=null){
        self::$key = $id;
        $code = rand(100000, 999999);
        return $code;
    }

    /**
     * 获取错误信息
     * @return mixed
     */
    static function Error(){
        return self::$_lastErrorMsg;
    }

    /**
     * 模板解析值
     * @param string $key
     * @param mixed $value
     */
    static function assign($key, $value){
        self::$rendData[$key] = $value;
    }

    /**
     * 获取当前的 session 键值
     * @return mixed
     */
    static function curCode(){
        $data = session(self::SessionCodeKey);
        return $data && is_array($data)? ($data['code'] ?? null) : null;
    }

    /**
     * 验证码认证
     * @param string $code
     * @param string $email
     * @return bool
     */
    static function verifyCode($code, $email){
        $isValid = false;
        $data = session(self::SessionCodeKey);
        if(!empty($data) && is_array($data)){
            self::$_lastErrorMsg = '';
            $refCode = $data['code'] ?? null;
            $time = $data['time'] ?? null;
            if($code && $time){
                $date1 = date_create(date('Y-m-d H:i:s', $time));
                $date2 = date_create('now');
                $interval = date_diff($date1, $date2);
                $min = $interval->format('%R%m');
                trace(["min=$min"]);
                $min = $min*1;
                if($min <= Config::get('email.minute')){
                    if($code == $refCode){
                        $isValid = true;
                    }else{
                        self::$_lastErrorMsg = '验证码无效，请重新输入';
                    }
                }else{
                    self::$_lastErrorMsg = '验证码已过期，请重新获取';
                }
            }else{
                self::$_lastErrorMsg = '您还没有获取到验证码，请先获取！';
            }
        }else{
            self::$_lastErrorMsg = '您还没有获取到验证码，请先获取！';
        }
        return $isValid;
    }
}